﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FileApps.LanguageFeatures;
using FileApps.Properties;
using System.IO;
using FileApps.Utilities;
using FileApps.GUI;

namespace FileApps
{
    public partial class MainForm : Form
    {

        //singleton which contains a property that lists all IMatchFeatures
        private SpecificationCollection featureColl = SpecificationCollection.GetInstance; 
        
        private LinesOfCode _loc;

        public string[] AllLines { get; private set; }
        public int TotalLines { get; private set; }
        public int CodeLines { get; private set; }
        public int EmptyLines { get; private set; }
        public int BracketLines { get; private set; }
        public int CommentLines { get; private set; }

        private int marginCharCount;

        public MainForm()
        {
            InitializeComponent();
            ClearGUI();
        }

        private void InitProperties()
        {
            TotalLines = _loc.TotalLines;
            CodeLines = _loc.CodeLines;
            EmptyLines = _loc.EmptyLines;
            BracketLines = _loc.BracketLines;
            CommentLines = _loc.CommentLines;
            
            //add line numbers
            List<string> newAllLinesList = new List<string>();
            int numberLength = TotalLines.ToString().Length;
            StringBuilder builder = new StringBuilder(numberLength);
            while (builder.Length < numberLength)
            {
                builder.Append("0");
            }
            
            marginCharCount = numberLength + 1;

            int lineCount = 1;
            foreach (var line in _loc.AllLines)
            {
                string s = lineCount.ToString(builder.ToString());
                newAllLinesList.Add(s + "\t" + line);
                lineCount++;
            }
            AllLines = newAllLinesList.ToArray();
        }

        private void UpdateGUI()
        {
            InitProperties();
            
            rtbCodeView.Lines = AllLines;
            
            tbTotalNrOfLines.Text = TotalLines.ToString();
            lblTotalPercent.Text = "100%";
            
            tbCodeLines.Text = CodeLines.ToString();
            lblCodePercent.Text = FormatPercentage(CodeLines);
            
            tbEmptyLines.Text = EmptyLines.ToString();
            lblEmptyPercent.Text = FormatPercentage(EmptyLines);
            
            tbBracketLines.Text = BracketLines.ToString();
            lblBracketsPercent.Text = FormatPercentage(BracketLines);

            tbCommentLines.Text = CommentLines.ToString();
            lblCommentsPercent.Text = FormatPercentage(CommentLines);
            SwitchEnableFields(true);
        }

        private string FormatPercentage(int lines)
        {
            if (TotalLines > 0)
            {
                double percentage = lines * 100d / TotalLines;
                return string.Format("{0:0.0} %", percentage);
            }
            return string.Empty;
        }

        private void DeselectAll()
        {
            rtbCodeView.Select(0, rtbCodeView.Text.Length);
            rtbCodeView.SelectionBackColor = SystemColors.Window;
            rtbCodeView.SelectionColor = SystemColors.WindowText;
            rtbCodeView.Select(0, 0);
            ClearManualField();
        }

        private void HighlightRows(Dictionary<int, string> dict)
        {
            DeselectAll();

            foreach(var item in dict)
            {
                var charIndex = rtbCodeView.GetFirstCharIndexFromLine(item.Key - 1);
                if (charIndex > -1)
                {
                    var lineLength = item.Value.Length;
                    var newLength = (lineLength == 0) ? 1 : lineLength;
                    rtbCodeView.Select(charIndex, newLength + marginCharCount);
                    rtbCodeView.SelectionBackColor = SystemColors.Highlight;
                    rtbCodeView.SelectionColor = SystemColors.HighlightText;
                }
            }
            ClearManualField();
        }

        private void ClearGUI()
        {
            SwitchEnableFields(false);
            _loc = null;
            rtbCodeView.Clear();
            rtbCodeView.Text = @"Use File -> Open to load a file.";
            tbTotalNrOfLines.Clear();
            tbCodeLines.Clear();
            tbEmptyLines.Clear();
            tbBracketLines.Clear();
            tbCommentLines.Clear();
            lblTotalPercent.Text = string.Empty;
            lblCodePercent.Text = string.Empty;
            lblCommentsPercent.Text = string.Empty;
            lblEmptyPercent.Text = string.Empty;
            lblBracketsPercent.Text = string.Empty;
            ClearManualField();
            ResetAllTextBoxColors();
        }

        private void SwitchEnableFields(bool enable)
        {
            tbTotalNrOfLines.Enabled = enable;
            tbCodeLines.Enabled = enable;
            tbEmptyLines.Enabled = enable;
            tbBracketLines.Enabled =enable;
            tbCommentLines.Enabled = enable;
            tbSelected.Enabled = enable;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {   
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.InitialDirectory = FolderHelper.GetDefaultFolder();
                ofd.Filter = PrepareFileFilter();
                ofd.Multiselect = false;
                if (ofd.ShowDialog() != DialogResult.Cancel)
                {
                    ClearGUI();
                    FileInfo fi = new FileInfo(ofd.FileName);
                    FolderHelper.SaveDefaultFolder(fi.Directory.FullName);
                    _loc = new LinesOfCode(ofd.FileName);
                    if (_loc.ParseSuccess)
                    {
                        UpdateGUI();
                    }
                    else
                    {
                        MessageBox.Show(string.Format("{0} could not be identified as a valid source file.",_loc.FileName)); 
                    }
                }
            }
        }

        private string PrepareFileFilter()
        {
            string fileFilter = string.Empty;
            foreach (var match in SpecificationCollection.MatchFeatureList)
            {
                fileFilter += match.FileFilter;
            }
            fileFilter += "All files|*.*";
            return fileFilter;
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClearGUI();
        }

        private void ClearManualField()
        {
            tbSelected.Clear();
            lblSelectedPercentage.Text = string.Empty;
        }

        private void tbCodeLines_Click(object sender, EventArgs e)
        {
            HighlightRows(_loc.CodeLineDictionary);
            ChangeColor(sender);
        }

        private void tbEmptyLines_Click(object sender, EventArgs e)
        {
            HighlightRows(_loc.EmptyLineDictionary);
            ChangeColor(sender);
        }

        private void tbCommentLines_Click(object sender, EventArgs e)
        {
            HighlightRows(_loc.CommentLineDictionary);
            ChangeColor(sender);
        }

        private void tbBracketLines_Click(object sender, EventArgs e)
        {
            HighlightRows(_loc.BracketLineDictionary);
            ChangeColor(sender);
        }

        private void ChangeColor(object sender)
        {
            ResetAllTextBoxColors();
            TextBox tb = (TextBox)sender;
            tb.BackColor = SystemColors.Highlight;
            tb.ForeColor = SystemColors.HighlightText;
        }

        private void ResetAllTextBoxColors()
        {
            tbTotalNrOfLines.BackColor = SystemColors.ControlLightLight;
            tbCodeLines.BackColor = SystemColors.ControlLightLight;
            tbCommentLines.BackColor = SystemColors.ControlLightLight;
            tbBracketLines.BackColor = SystemColors.ControlLightLight;
            tbEmptyLines.BackColor = SystemColors.ControlLightLight;
            tbSelected.BackColor = SystemColors.ControlLightLight;

            tbTotalNrOfLines.ForeColor = SystemColors.ControlText;
            tbCodeLines.ForeColor = SystemColors.ControlText;
            tbCommentLines.ForeColor = SystemColors.ControlText;
            tbBracketLines.ForeColor = SystemColors.ControlText;
            tbEmptyLines.ForeColor = SystemColors.ControlText;
            tbSelected.ForeColor = SystemColors.ControlText;
        }

        private void tbTotalNrOfLines_Click(object sender, EventArgs e)
        {
            HighlightRows(new Dictionary<int, string>());
            ResetAllTextBoxColors();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ClearGUI();
            Application.Exit();
        }

        private void CalculateSelectedLines(RichTextBox rtb)
        {
            int startChar = rtb.SelectionStart;
            int selectionLength = rtbCodeView.SelectionLength;
            if (selectionLength > 0)
            {
                int startLine = rtb.GetLineFromCharIndex(startChar);
                int endLine = rtb.GetLineFromCharIndex(selectionLength + startChar - 1);
                int totalLines = endLine - startLine + 1;
                tbSelected.Text = totalLines.ToString();
                lblSelectedPercentage.Text = FormatPercentage(totalLines);
            }
            else 
            {
                ClearManualField();
            }
        }

        private void rtbCodeView_SelectionChanged(object sender, EventArgs e)
        {
            CalculateSelectedLines((RichTextBox)sender);
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LOCAboutBox about = new LOCAboutBox();
            about.ShowDialog(this);
        }
    }
}
